﻿Option Strict Off

Imports System.Data.Common
Imports System.Runtime.CompilerServices

Public Class ImportarFilemaker

    Property Contexto As New AsindoContext
    Property dirNula As Dirección
    Property dirRepo As DirecciónRepository

    Property itemWriter As New System.IO.StringWriter

    Public Sub Importar()
        dirRepo = New DirecciónRepository(Contexto)
        BorrarDatosActuales()
        CopiarDatosFileMaker()

    End Sub

    Public Sub BorrarDatosActuales()
        Truncate("Avisos")
        Truncate("Personas_Paciente")
        Truncate("Personas_PediatraAsindo")
        Truncate("Personas_Pediatra")
        Truncate("Personas")
        Truncate("Direcciones")
        Truncate("TiposVía")
        Truncate("Poblaciones")
        Truncate("Sociedades")
    End Sub

    Private Sub CopiarDatosFileMaker()
        Console.WriteLine("Sociedades...")
        CopiarSociedades()
        Contexto.SaveChanges()
        Console.WriteLine("Tipos via")
        CopiarTiposVía()
        Contexto.SaveChanges()
        Console.WriteLine("poblaciones")
        CopiarPoblaciones()
        Contexto.SaveChanges()
        Console.WriteLine("direcciones")
        CopiarDirecciones()
        Contexto.SaveChanges()
        Console.WriteLine("pediatras asindo")
        CopiarPediatrasAsindo()
        Contexto.SaveChanges()
        Console.WriteLine("pediatras")
        CopiarPediatras()
        Contexto.SaveChanges()
        Console.WriteLine("pacientes")
        CopiarPacientes()
        Console.WriteLine("avisos")
        CopiarAvisos()
    End Sub

    Private Sub CopiarSociedades()
        Dim validator As New SociedadValidator()
        Dim soc As Sociedad
        For Each socFM5 In Contexto.ENTIDAD_FP5
            soc = New Sociedad With {.Nombre = socFM5.APELLIDO1EN, .IdFileMaker = socFM5.HISTORIAEN}
            Contexto.Sociedades.AddObject(soc)
        Next
        soc = New Sociedad With {.Nombre = "CENTRO ASEGURADOR - MEDICENTRO"}

        Contexto.Sociedades.AddObject(soc)
    End Sub
    Dim madrid As Población

    Private Sub CopiarPoblaciones()
        madrid = GuardarPoblación("Madrid").Item1
    End Sub

    Private Sub CopiarDirecciones()
        Dim validator As New DirecciónValidator()
        dirNula = New Dirección With {
                                            .TipoVía = defTipoVía,
                                            .Vía = "Desconocida",
                                            .Número = 0,
                                            .Portal = "",
                                            .Piso = Nothing,
                                            .Letra = "",
                                            .CódigoPostal = "00000",
                                            .Población = madrid}

        Contexto.Direcciones.AddObject(dirNula)
    End Sub

    Dim defTipoVía As TipoVía
    Private Sub CopiarTiposVía()
        defTipoVía = New TipoVía With {.Nombre = "Calle"}
        Contexto.TiposVía.AddObject(defTipoVía)
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Finca"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Avenida"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Camino"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Pasaje"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Parque"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Paseo"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Plaza"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Carretera"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Glorieta"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Travesía"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Urbanización"})
        Contexto.TiposVía.AddObject(New TipoVía With {.Nombre = "Ronda"})
    End Sub

    Private Function GuardarPoblación(ByVal pob As String) As Tuple(Of Población, String)
        Dim cp As String
        pob = pob.FixName

        If pob Is Nothing Then
            itemWriter.WriteLine("Sin población. Asumiremos Madrid", pob)
        End If

        If pob IsNot Nothing AndAlso pob.Length >= 5 AndAlso pob.Take(5).All(Function(ch) ch.IsDigit) Then
            itemWriter.WriteLine("La población empieza por número ({0}). Asumiremos C.P. + población", pob)
            cp = pob.Substring(0, 5)
            pob = pob.Substring(6).Trim(" "c, "."c)
        Else
            cp = Nothing
        End If

        Dim objpob = Contexto.Poblaciones.SingleOrDefault(Function(pobl) pobl.Nombre = pob)
        If objpob Is Nothing Then
            If String.IsNullOrEmpty(pob) Then
                itemWriter.WriteLine("Población nula")
                objpob = madrid
            Else
                objpob = New Población With {.Nombre = pob}
                Contexto.Poblaciones.AddObject(objpob)
            End If
        End If

        Return New Tuple(Of Población, String)(objpob, cp)
    End Function

    Private Function GuardarDirección(
        ByVal tipoVía As String,
        ByVal vía As String,
        ByVal núm As Integer?,
        ByVal portal As String,
        ByVal piso As Integer?,
        ByVal letra As String,
        ByVal cp As String,
        ByVal pob As String) As Dirección

        tipoVía = tipoVía.UpperFirst
        Select Case tipoVía
            Case "Avda."
                tipoVía = "Avenida"
            Case "Cmno.", "Camino."
                tipoVía = "Camino"
            Case "Psaje."
                tipoVía = "Pasaje"
            Case "Pque."
                tipoVía = "Parque"
            Case "Gta."
                tipoVía = "Glorieta"
            Case "Trav.", "Travesia"
                tipoVía = "Travesía"
            Case "Urb.", "Urbanizacion"
                tipoVía = "Urbanización"
        End Select

        If cp IsNot Nothing AndAlso cp.Length > 5 Then
            cp = cp.Substring(0, 5)
        End If

        Dim tuppob = GuardarPoblación(pob)
        Dim objpob = tuppob.Item1
        vía = If(vía, "Desconocida")
        vía = vía.FixName
        cp = If(cp, If(tuppob.Item2, "00000"))
        núm = If(núm, 0)

        Dim tvía As TipoVía
        tvía = Contexto.TiposVía.SingleOrDefault(Function(tvia) tvia.Nombre = tipoVía)
        If tvía Is Nothing Then
            itemWriter.WriteLine("Tipo de vía no reconocido: [{0}]", tipoVía)
            itemWriter.WriteLine("Vía: [{0}]", vía)
            tvía = defTipoVía
        End If
        Dim nueva = New Dirección With {
            .TipoVía = tvía,
            .Vía = vía,
            .Número = núm,
            .Portal = portal,
            .Piso = piso,
            .Letra = letra,
            .CódigoPostal = cp,
            .Población = objpob}

        Return dirRepo.AddIfNotExists(nueva, True)
    End Function

    Private Sub CopiarPediatrasAsindo()
        Dim validator As New PediatraAsindoValidator()

        For Each asindoFM5 In Contexto.ASINDO_FP5.ToList
            Dim pedAsindo As New PediatraAsindo With {
                .Activo = True,
                .Apellido1 = asindoFM5.APELLIDO1ASINDO.FixName,
                .Apellido2 = asindoFM5.APELLIDO2ASINDO2.FixName,
                .Nombre = asindoFM5.NOMBREASINDO.FixName,
                .FechaAlta = asindoFM5.FECHAASINDO,
                .Dirección = GuardarDirección(asindoFM5.VIA, asindoFM5.DOMICILIO, asindoFM5.numero.ToInt, "", asindoFM5.piso.ToInt, "", asindoFM5.CODPOSTAL, asindoFM5.CIUDAD),
                .IdFileMakerAsindo = CInt(asindoFM5.HISTORIAASIN)
            }

            If pedAsindo.IdFileMakerAsindo = 1 Then
                pedAsindo.Usuario = "llaorden"
                pedAsindo.Contraseña = "sanimed4"
            End If
            If pedAsindo.IdFileMakerAsindo = 2 Then
                pedAsindo.Usuario = "fpozo"
                pedAsindo.Contraseña = "278491fp"
            End If
            If Check(validator.Validate(pedAsindo)) Then
                Contexto.Personas.AddObject(pedAsindo)
            End If
            Volcar("Pediatra ASINDO " & asindoFM5.HISTORIAASIN)
        Next
    End Sub

    Private Function Check(ByVal result As FluentValidation.Results.ValidationResult) As Boolean
        If result.IsValid Then
            Return True
        Else
            For Each valError In result.Errors
                itemWriter.WriteLine(valError.ErrorMessage)
            Next
            Return False
        End If
    End Function

    Private Sub CopiarPediatras()
        Dim validator As New PediatraValidator()
        For Each pediatraFM5 In Contexto.PEDIATRAS_FP5
            Dim ped As New Pediatra With {
                .IdFileMaker = pediatraFM5.PHISTORIA,
                .Apellido1 = pediatraFM5.APELLIDO1.FixName,
                .Apellido2 = pediatraFM5.APELLIDO2.FixName,
                .Nombre = pediatraFM5.NOMBRE.FixName,
                .Dirección = dirNula,
                .FechaAlta = pediatraFM5.FECHAPRESENTACION
            }

            Contexto.Personas.AddObject(ped)
            Volcar("Pediatra " & pediatraFM5.PHISTORIA)
        Next
    End Sub

    Private Function Join2(ByVal sa() As String) As String
        Dim addedFirst As Boolean = False
        Dim result As New System.Text.StringBuilder
        For Each s In sa
            If Not String.IsNullOrWhiteSpace(s) Then
                If addedFirst Then
                    result.Append(", " & s)
                Else
                    result.Append(s)
                    addedFirst = True
                End If
            End If
        Next
        Return result.ToString
    End Function

    Private Function CorregirSociedad(ByVal soc As String) As String
        Select Case soc
            Case "asiscar", "assiscar"
                Return "ASSIST CARD"
            Case "MAPFRE", "CAJASALUD", "MEDYSALUD"
                Return "MAPFRE-CAJASALUD-MEDYSALUD"
            Case "MEDIFIAC-GROUPAMA", "MEDITEC-MEDIFIAC-GRUPAMA", "GRUPAMA", "PLUS ULTRA", "MEDITEC"
                Return "MEDITEC-MEDIFIAC-GRUPAMA-PLUS ULTRA"
            Case "WINTHERTHUR"
                Return "AXA-WINTHERTHUR"
            Case Else
                Return soc
        End Select
    End Function

    Private Sub CopiarPacientes()
        Dim validator As New PacienteValidator()
        Dim query = From pacienteFM5 In Contexto.PACIENTES_FP5 Join familiaFM5 In Contexto.FAMILIA_FP5 On pacienteFM5.familia Equals familiaFM5.HISTORIA

        For Each pacfamFM5 In query.ToList
            Dim pacienteFM5 = pacfamFM5.pacienteFM5
            Dim familiafm5 = pacfamFM5.familiaFM5
            Dim paciente As Paciente

            familiafm5.SOCIEDAD = CorregirSociedad(familiafm5.SOCIEDAD)

            Dim orden As Integer? = Nothing

            If pacienteFM5.HIJO <> "" Then
                orden = CInt(pacienteFM5.HIJO)
            End If
            Dim tels = ObtenerTeléfonos(familiafm5.TELEFONO, familiafm5.TELEFONO2, familiafm5.TELEFONO3)
            Dim piso = familiafm5.piso.ToInt
            Dim letra = ""
            If Not piso.HasValue Then
                letra = familiafm5.piso
            End If
            paciente = New Paciente With {
                .IdFileMaker = pacienteFM5.PACIHISTORIA,
                .Apellido1 = pacienteFM5.PACIAPELLIDO1.FixName,
                .Apellido2 = pacienteFM5.PACIAPELLIDO2.FixName,
                .Nombre = pacienteFM5.PACINOMBRE.FixName,
                .Dirección = GuardarDirección(familiafm5.VIA, familiafm5.DOMICILIO, familiafm5.numero.ToInt, "", piso, letra, familiafm5.CODPOSTAL, familiafm5.CIUDAD),
                .FechaAlta = pacienteFM5.FECHAPRESENTACION,
                .OrdenHermanos = orden,
                .Sexo = If(pacienteFM5.SEXO = "", Nothing, pacienteFM5.SEXO.First),
                .Alarmas = Join2({pacienteFM5.alarma1, pacienteFM5.alarma2, pacienteFM5.alarma3, pacienteFM5.alarma4}),
                .PediatraHabitual = Contexto.Personas.OfType(Of Pediatra).SingleOrDefault(Function(pediatra) pediatra.IdFileMaker = pacienteFM5.PEDIATRAS),
                .FechaNacimiento = pacienteFM5.FechaNacimiento,
                .Sociedad = Contexto.Sociedades.SingleOrDefault(Function(sociedad) sociedad.Nombre = familiafm5.SOCIEDAD),
                .Teléfono1 = tels(0),
                .Teléfono2 = tels(1),
                .Teléfono3 = tels(2),
                .Observaciones = familiafm5.observa
            }
            Try
                If Check(validator.Validate(paciente)) Then
                    Contexto.Personas.AddObject(paciente)
                Else
                    Contexto.Personas.Detach(paciente)
                End If
                Contexto.SaveChanges()
            Catch ex As UpdateException
                itemWriter.WriteLine("Error al actualizar paciente {0}: {1}", pacienteFM5.PACIHISTORIA, ex.InnerException.Message)
                Contexto.Personas.DeleteObject(paciente)
            Catch ex As EntityException
                itemWriter.WriteLine("Error con paciente {0}" & pacienteFM5.PACIHISTORIA)
                Contexto.Personas.DeleteObject(paciente)
            End Try
            Volcar("Paciente " & pacienteFM5.PACIHISTORIA)
        Next
    End Sub

    Private Function ObtenerTeléfonos(ByVal tel1 As String, ByVal tel2 As String, ByVal tel3 As String) As String()
        Dim telJuntos = String.Format("{0} {1} {2}", tel1, tel2, tel3)
        Dim result(2) As String
        Dim telActual As New StringBuilder
        Dim estado As Integer = 0
        Dim idxActual As Integer = 0
        For Each caracter In telJuntos
            Select Case estado
                Case 0
                    If caracter.IsDigit Then
                        telActual.Append(caracter)
                    Else
                        estado = 1
                        result(idxActual) = telActual.ToString
                        telActual.Clear()
                        idxActual += 1
                        If idxActual = 3 Then
                            Return result
                        End If
                    End If
                Case 1
                    If caracter.IsDigit Then
                        estado = 0
                        telActual.Append(caracter)
                    Else

                    End If
            End Select
        Next
        If telActual.Length > 0 Then
            result(idxActual) = telActual.ToString
        End If
        Return result
    End Function

    Private Sub Volcar(ByVal titulo As String)
        Dim log = itemWriter.ToString
        If String.IsNullOrEmpty(log) Then
        Else
            Console.WriteLine(titulo)
            Console.Write(itemWriter.ToString)
            itemWriter.GetStringBuilder.Clear()
        End If
    End Sub

    Private Sub CopiarAvisos()
        Dim validator As New AvisoValidator()
        Dim query = From avisoFM5 In Contexto.VISITAS_FP5 Join pedFM5 In Contexto.ASINDO_FP5 On avisoFM5.PROASINDO Equals pedFM5.DR

        For Each avisopedFM5 In query.ToList
            Dim avisoFM5 = avisopedFM5.avisoFM5
            Dim pedAsindoFM5 = avisopedFM5.pedFM5
            Dim paciente = Contexto.Personas.OfType(Of Paciente).SingleOrDefault(Function(pac) pac.IdFileMaker = avisoFM5.PACIVISI)
            Dim fecha As Date?

            If avisoFM5.FECHAVISITA.HasValue Then
                If avisoFM5.horaavi.HasValue Then
                    fecha = avisoFM5.FECHAVISITA.Value.Add(avisoFM5.horaavi.Value)
                Else
                    fecha = avisoFM5.FECHAVISITA
                End If
            Else
                fecha = Nothing
            End If

            Dim aviso As New Aviso With {
                .IdFileMaker = avisoFM5.NUMEVISI,
                .Fecha = fecha,
                .Paciente = paciente,
                .Honorarios = avisoFM5.IMPORTE,
                .PediatraAsindo = Contexto.Personas.OfType(Of PediatraAsindo).SingleOrDefault(Function(pedAsindo) pedAsindo.IdFileMakerAsindo = pedAsindoFM5.HISTORIAASIN),
                .Dirección = If(paciente Is Nothing, Nothing, paciente.Dirección),
                .Diagnóstico = Join2({avisoFM5.diag1, avisoFM5.diag2, avisoFM5.diag3, avisoFM5.diag4}),
                .Observaciones = avisoFM5.OBSERVACIONES
            }
            Try
                If Check(validator.Validate(aviso)) Then _
                    Contexto.Avisos.AddObject(aviso)
                Contexto.SaveChanges()
            Catch ex As UpdateException
                itemWriter.WriteLine("Error al actualizar aviso {0}: {1}", avisoFM5.NUMEVISI, ex.InnerException.Message)
                Contexto.Avisos.DeleteObject(aviso)
            End Try
            Volcar("Aviso " & avisoFM5.NUMEVISI)
        Next
    End Sub

    Private Sub Truncate(ByVal tabla As String)
        Dim entityConnection = DirectCast(Contexto.Connection, System.Data.EntityClient.EntityConnection)
        Dim conn As DbConnection = entityConnection.StoreConnection
        Dim sql = String.Format("DELETE FROM {0}", tabla)

        Dim initialState As ConnectionState = conn.State
        Try
            If initialState <> ConnectionState.Open Then
                conn.Open()
            End If
            ' open connection if not already open
            Using cmd As DbCommand = conn.CreateCommand()
                cmd.CommandText = sql
                cmd.ExecuteNonQuery()
            End Using
        Finally
            If initialState <> ConnectionState.Open Then
                conn.Close()
                ' only close connection if not initially open
            End If
        End Try
    End Sub

End Class

Public Module StringExtensions

    <Extension()>
    Public Function UpperFirst(ByVal s As String) As String
        If String.IsNullOrEmpty(s) Then
            Return s
        ElseIf s.Length = 1 Then
            Return s.ToUpper
        Else
            Return s.Substring(0, 1).ToUpper & s.Substring(1).ToLower
        End If
    End Function

    <Extension()>
    Public Function ToInt(ByVal s As String) As Integer?
        If String.IsNullOrEmpty(s) Then
            Return Nothing
        ElseIf IsNumeric(s) Then
            Return CInt(s)
        ElseIf s = "B" OrElse s.ToLower = "bajo" Then
            Return 0
        Else
            Return Nothing
        End If
    End Function

    Private ReadOnly partículas() As String = {"de", "el", "la", "los", "las", "y", "del"}
    Private ReadOnly artículos() As String = {"el", "la", "los", "las"}

    <Extension()>
    Public Function FixName(ByVal s As String) As String
        If s Is Nothing Then
            Return Nothing
        End If
        Dim sa() = s.Trim.ToLower.Split(" "c)
        Dim result As New List(Of String)

        For Each piece In sa
            If piece <> "" Then
                If Array.IndexOf(partículas, piece) = -1 Then
                    ' No es partícula
                    Dim sa2() = piece.Split("-"c)
                    If sa2.Length = 1 Then
                        result.Add(piece.UpperFirst)
                    Else
                        Dim joined = Join(sa2.Select(Function(piece2) piece2.UpperFirst).ToArray)
                        result.Add(joined)
                    End If
                ElseIf Array.IndexOf(artículos, piece) = -1 Then
                    ' Es partícula pero no es artículo: siempre minúsculas
                    result.Add(piece)
                Else
                    ' El artículo lo ponemos en mayúscula si es la primera palabra
                    If result.Count = 0 Then
                        result.Add(piece.UpperFirst)
                    Else
                        result.Add(piece)
                    End If
                End If
            End If
        Next

        Return If(Join(result.ToArray), "")
    End Function

    <Extension()>
    Public Function IsDigit(ByVal ch As Char) As Boolean
        Return Char.IsDigit(ch)
    End Function

    Public Sub ProcesarLetra(ByVal direc As Dirección)
        Dim sinSímbolos = Regex.Replace(direc.Letra, "[ºª,.]", " ")
        Dim tokens = sinSímbolos.Split(" "c).Select(Function(str) str.Trim.ToUpper).Where(Function(str) Not String.IsNullOrEmpty(str)).ToList
        Select Case tokens.Count
            Case 0
            Case 1
            Case 2
                If IsNumeric(tokens(0)) Then
                    direc.Piso = CInt(tokens(0))
                    If tokens(1).StartsWith("IZQ") Then
                        direc.Letra = "IZQ"
                    ElseIf tokens(1).StartsWith("DER") Then
                        direc.Letra = "DER"
                    ElseIf tokens(1).StartsWith("CEN") Then
                        direc.Letra = "CEN"
                    Else
                        direc.Letra = tokens(1)
                    End If
                ElseIf tokens(0) = "BAJO" Then
                    direc.Piso = 0
                    If tokens(1).StartsWith("IZQ") Then
                        direc.Letra = "IZQ"
                    ElseIf tokens(1).StartsWith("DER") Then
                        direc.Letra = "DER"
                    ElseIf tokens(1).StartsWith("CEN") Then
                        direc.Letra = "CEN"
                    Else
                        direc.Letra = tokens(1)
                    End If
                ElseIf tokens(0).StartsWith("CH") Then
                    direc.Piso = tokens(1)

                End If
            Case 3
                If IsNumeric(tokens(0)) AndAlso tokens(1) = "PUERTA" AndAlso IsNumeric(tokens(2)) Then
                    direc.Piso = CInt(tokens(0))
                    direc.Letra = tokens(2)
                End If
            Case Else

        End Select
    End Sub
End Module